package com.gitee.wsl.struct.grammar.ast.process.marker.block.impl


import com.gitee.wsl.struct.grammar.ast.node.NodeType
import com.gitee.wsl.struct.grammar.ast.process.constraints.TextReadConstraints
import com.gitee.wsl.struct.grammar.ast.process.constraints.ext.applyToNextLineAndAddModifiers
import com.gitee.wsl.struct.grammar.ast.process.constraints.ext.calcNumberOfConsequentEols
import com.gitee.wsl.struct.grammar.ast.process.constraints.ext.getCharsEaten
import com.gitee.wsl.struct.grammar.ast.process.constraints.ext.upstreamWith
import com.gitee.wsl.struct.grammar.ast.process.marker.InterruptsParagraphCheck
import com.gitee.wsl.struct.grammar.ast.process.marker.ProductionHolder
import com.gitee.wsl.struct.grammar.ast.process.marker.block.MarkerBlock
import com.gitee.wsl.struct.grammar.ast.process.marker.block.MarkerBlockImpl
import com.gitee.wsl.text.reader.line.LookaheadText


class ParagraphMarkerBlock(constraints: TextReadConstraints,
                           marker: ProductionHolder.Marker,
                           val interruptsParagraph: InterruptsParagraphCheck
) : MarkerBlockImpl(constraints, marker) {

    override fun allowsSubBlocks(): Boolean = false

    override fun isInterestingOffset(pos: LookaheadText.Position): Boolean = true

    override fun getDefaultAction(): MarkerBlock.ClosingAction {
        return MarkerBlock.ClosingAction.DONE
    }

    override fun calcNextInterestingOffset(pos: LookaheadText.Position): Int {
        return pos.nextLineOrEofOffset
    }

    override fun doProcessToken(pos: LookaheadText.Position,
                                currentConstraints: TextReadConstraints
    ): MarkerBlock.ProcessingResult {

        if (pos.offsetInCurrentLine != -1) {
            return MarkerBlock.ProcessingResult.CANCEL
        }

        require(pos.offsetInCurrentLine == -1)

        if (constraints.calcNumberOfConsequentEols(pos) >= 2) {
            return MarkerBlock.ProcessingResult.DEFAULT
        }

        val nextLineConstraints = constraints.applyToNextLineAndAddModifiers(pos)
        if (!nextLineConstraints.upstreamWith(constraints)) {
            return MarkerBlock.ProcessingResult.DEFAULT
        }

        val posToCheck = pos.nextPosition(1 + nextLineConstraints.getCharsEaten(pos.currentLineText))
        if (posToCheck == null || interruptsParagraph(posToCheck, nextLineConstraints)) {
            return MarkerBlock.ProcessingResult.DEFAULT
        }

        return MarkerBlock.ProcessingResult.CANCEL
    }

    override fun getDefaultNodeType(): NodeType {
        return NodeType.PARAGRAPH
    }

}
